﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Diagnostics.CodeAnalysis
Imports System.Globalization
Imports System.Runtime.InteropServices
Imports System.Text

Namespace System.Workflow.Activities.Rules
    Friend Class Scanner
        ' Methods
        Friend Sub New(ByVal inputString As String)
            Me.inputString = inputString
            Me.inputStringLength = inputString.Length
        End Sub

        Friend Shared Sub AddKeywordsStartingWith(ByVal upperFirstCharacter As Char, ByVal list As ArrayList)
            Dim pair As KeyValuePair([Of] String, KeywordInfo)
            For Each pair In Scanner.keywordMap
                If (Char.ToUpper(pair.Key.Chars(0), CultureInfo.InvariantCulture) = upperFirstCharacter) Then
                    list.Add(New IntellisenseKeyword(pair.Key))
                End If
            Next
        End Sub

        Private Shared Function CreateKeywordMap() As Dictionary([Of] String, KeywordInfo)
            Dim dictionary As New Dictionary([Of] String, KeywordInfo)(&H1B)
            dictionary.Add("mod", New KeywordInfo(TokenID.Modulus))
            dictionary.Add("and", New KeywordInfo(TokenID.And))
            dictionary.Add("or", New KeywordInfo(TokenID.Or))
            dictionary.Add("not", New KeywordInfo(TokenID.Not))
            dictionary.Add("true", New KeywordInfo(TokenID.True, True))
            dictionary.Add("false", New KeywordInfo(TokenID.False, False))
            dictionary.Add("null", New KeywordInfo(TokenID.Null, Nothing))
            dictionary.Add("nothing", New KeywordInfo(TokenID.Null, Nothing))
            dictionary.Add("this", New KeywordInfo(TokenID.This))
            dictionary.Add("me", New KeywordInfo(TokenID.This))
            dictionary.Add("in", New KeywordInfo(TokenID.In))
            dictionary.Add("out", New KeywordInfo(TokenID.Out))
            dictionary.Add("ref", New KeywordInfo(TokenID.Ref))
            dictionary.Add("halt", New KeywordInfo(TokenID.Halt))
            dictionary.Add("update", New KeywordInfo(TokenID.Update))
            dictionary.Add("new", New KeywordInfo(TokenID.New))
            dictionary.Add("char", New KeywordInfo(TokenID.TypeName, GetType(Char)))
            dictionary.Add("byte", New KeywordInfo(TokenID.TypeName, GetType(Byte)))
            dictionary.Add("sbyte", New KeywordInfo(TokenID.TypeName, GetType([SByte])))
            dictionary.Add("short", New KeywordInfo(TokenID.TypeName, GetType(Short)))
            dictionary.Add("ushort", New KeywordInfo(TokenID.TypeName, GetType(UInt16)))
            dictionary.Add("int", New KeywordInfo(TokenID.TypeName, GetType(Integer)))
            dictionary.Add("uint", New KeywordInfo(TokenID.TypeName, GetType(UInt32)))
            dictionary.Add("long", New KeywordInfo(TokenID.TypeName, GetType(Long)))
            dictionary.Add("ulong", New KeywordInfo(TokenID.TypeName, GetType(UInt64)))
            dictionary.Add("float", New KeywordInfo(TokenID.TypeName, GetType(Single)))
            dictionary.Add("double", New KeywordInfo(TokenID.TypeName, GetType(Double)))
            dictionary.Add("decimal", New KeywordInfo(TokenID.TypeName, GetType(Decimal)))
            dictionary.Add("bool", New KeywordInfo(TokenID.TypeName, GetType(Boolean)))
            dictionary.Add("string", New KeywordInfo(TokenID.TypeName, GetType(String)))
            dictionary.Add("object", New KeywordInfo(TokenID.TypeName, GetType(Object)))
            Return dictionary
        End Function

        Private Function CurrentChar() As Char
            If (Me.currentPosition >= Me.inputStringLength) Then
                Return ChrW(0)
            End If
            Return Me.inputString.Chars(Me.currentPosition)
        End Function

        Private Shared Function HexValue(ByVal ch As Char) As Integer
            Dim num As Integer = -1
            If Char.IsDigit(ch) Then
                Return (ch - "0"c)
            End If
            If ((ch >= "a"c) AndAlso (ch <= "f"c)) Then
                Return ((ch - "a"c) + 10)
            End If
            If ((ch >= "A"c) AndAlso (ch <= "F"c)) Then
                num = ((ch - "A"c) + 10)
            End If
            Return num
        End Function

        Private Function NextChar() As Char
            If (Me.currentPosition = (Me.inputStringLength - 1)) Then
                Me.currentPosition += 1
                Return ChrW(0)
            End If
            Me.currentPosition += 1
            Return Me.CurrentChar
        End Function

        <SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")> _
        Private Function NextToken() As Token
            Dim message As String = Nothing
            Dim token As Token
            Dim unknown As TokenID = TokenID.Unknown
            Dim ch As Char = Me.CurrentChar
            ch = Me.SkipWhitespace(ch)
            If (ch = ChrW(0)) Then
                Return New Token(TokenID.EndOfInput, Me.currentPosition, Nothing)
            End If
            Me.tokenStartPosition = Me.currentPosition
            Me.tokenValue = Nothing
            If Char.IsDigit(ch) Then
                unknown = Me.ScanNumber
            ElseIf Char.IsLetter(ch) Then
                unknown = Me.ScanKeywordOrIdentifier
            Else
                Select Case ch
                    Case "!"c
                        unknown = TokenID.Not
                        If (Me.NextChar = "="c) Then
                            Me.NextChar
                            unknown = TokenID.NotEqual
                        End If
                        goto Label_0397
                    Case """"c
                        unknown = Me.ScanStringLiteral
                        Me.NextChar
                        goto Label_0397
                    Case "%"c
                        unknown = TokenID.Modulus
                        Me.NextChar
                        goto Label_0397
                    Case "&"c
                        unknown = TokenID.BitAnd
                        If (Me.NextChar = "&"c) Then
                            Me.NextChar
                            unknown = TokenID.And
                        End If
                        goto Label_0397
                    Case "'"c
                        unknown = Me.ScanCharacterLiteral
                        Me.NextChar
                        goto Label_0397
                    Case "("c
                        unknown = TokenID.LParen
                        Me.NextChar
                        goto Label_0397
                    Case ")"c
                        unknown = TokenID.RParen
                        Me.NextChar
                        goto Label_0397
                    Case "*"c
                        unknown = TokenID.Multiply
                        Me.NextChar
                        goto Label_0397
                    Case "+"c
                        unknown = TokenID.Plus
                        Me.NextChar
                        goto Label_0397
                    Case ","c
                        unknown = TokenID.Comma
                        Me.NextChar
                        goto Label_0397
                    Case "-"c
                        unknown = TokenID.Minus
                        Me.NextChar
                        goto Label_0397
                    Case "."c
                        unknown = TokenID.Dot
                        If Not Char.IsDigit(Me.PeekNextChar) Then
                            Me.NextChar
                        Else
                            unknown = Me.ScanDecimal
                        End If
                        goto Label_0397
                    Case "/"c
                        unknown = TokenID.Divide
                        Me.NextChar
                        goto Label_0397
                    Case ";"c
                        unknown = TokenID.Semicolon
                        Me.NextChar
                        goto Label_0397
                    Case "<"c
                        unknown = TokenID.Less
                        Select Case Me.NextChar
                            Case "="c
                                Me.NextChar
                                unknown = TokenID.LessEqual
                                Exit Select
                            Case ">"c
                                Me.NextChar
                                unknown = TokenID.NotEqual
                                Exit Select
                        End Select
                        goto Label_0397
                    Case "="c
                        unknown = TokenID.Assign
                        If (Me.NextChar = "="c) Then
                            Me.NextChar
                            unknown = TokenID.Equal
                        End If
                        goto Label_0397
                    Case ">"c
                        unknown = TokenID.Greater
                        If (Me.NextChar = "="c) Then
                            Me.NextChar
                            unknown = TokenID.GreaterEqual
                        End If
                        goto Label_0397
                    Case "@"c
                        ch = Me.NextChar
                        If (ch <> """"c) Then
                            message = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidCharacter, New Object() { ch })
                            Throw New RuleSyntaxException(&H17B, message, Me.tokenStartPosition)
                        End If
                        unknown = Me.ScanVerbatimStringLiteral
                        Me.NextChar
                        goto Label_0397
                    Case "["c
                        unknown = TokenID.LBracket
                        Me.NextChar
                        goto Label_0397
                    Case "]"c
                        unknown = TokenID.RBracket
                        Me.NextChar
                        goto Label_0397
                    Case "_"c
                        unknown = Me.ScanKeywordOrIdentifier
                        goto Label_0397
                    Case "{"c
                        unknown = TokenID.LCurlyBrace
                        Me.NextChar
                        goto Label_0397
                    Case "|"c
                        unknown = TokenID.BitOr
                        If (Me.NextChar = "|"c) Then
                            Me.NextChar
                            unknown = TokenID.Or
                        End If
                        goto Label_0397
                    Case "}"c
                        unknown = TokenID.RCurlyBrace
                        Me.NextChar
                        goto Label_0397
                End Select
                Me.NextChar
                message = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidCharacter, New Object() { ch })
                Throw New RuleSyntaxException(&H17B, message, Me.tokenStartPosition)
            End If
        Label_0397:
            token = New Token(unknown, Me.tokenStartPosition, Me.tokenValue)
            Me.currentToken = unknown
            Return token
        End Function

        Private Function PeekNextChar() As Char
            If (Me.currentPosition = (Me.inputStringLength - 1)) Then
                Return ChrW(0)
            End If
            Dim num As Integer = (Me.currentPosition + 1)
            If (num >= Me.inputStringLength) Then
                Return ChrW(0)
            End If
            Return Me.inputString.Chars(num)
        End Function

        Private Function ScanCharacter(<Out> ByRef isEscaped As Boolean) As Char
            isEscaped = False
            Dim ch As Char = Me.NextChar
            If (ch <> "\"c) Then
                Return ch
            End If
            isEscaped = True
            ch = Me.NextChar
            Select Case ch
                Case """"c, "'"c
                    Return ch
                Case "0"c
                    Return ChrW(0)
                Case "n"c
                    Return ChrW(10)
                Case "r"c
                    Return ChrW(13)
                Case "t"c
                    Return ChrW(9)
                Case "u"c
                    Return Me.ScanUnicodeEscapeSequence
                Case "v"c
                    Return ChrW(11)
                Case "f"c
                    Return ChrW(12)
                Case "a"c
                    Return ChrW(7)
                Case "b"c
                    Return ChrW(8)
                Case "\"c
                    Return ch
            End Select
            Dim message As String = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidEscapeSequence, New Object() { ch })
            Throw New RuleSyntaxException(380, message, (Me.currentPosition - 1))
        End Function

        Private Function ScanCharacterLiteral() As TokenID
            Dim isEscaped As Boolean = False
            Dim ch As Char = Me.ScanCharacter(isEscaped)
            Me.tokenValue = ch
            If (Me.NextChar <> "'"c) Then
                Throw New RuleSyntaxException(&H17D, Messages.Parser_UnterminatedCharacterLiteral, Me.currentPosition)
            End If
            Return TokenID.CharacterLiteral
        End Function

        Private Function ScanDecimal() As TokenID
            Dim str As String
            Dim integerLiteral As TokenID
            Dim unsuffixedInteger As NumberKind = NumberKind.UnsuffixedInteger
            Dim buffer As New StringBuilder
            Dim c As Char = Me.CurrentChar
            Do While Char.IsDigit(c)
                buffer.Append(c)
                c = Me.NextChar
            Loop
            Select Case c
                Case "d"c, "D"c
                    unsuffixedInteger = NumberKind.Double
                    Me.NextChar
                    Exit Select
                Case "e"c, "E"c
                    buffer.Append("e"c)
                    Me.NextChar
                    unsuffixedInteger = Me.ScanExponent(buffer)
                    Exit Select
                Case "f"c, "F"c
                    unsuffixedInteger = NumberKind.Float
                    Me.NextChar
                    Exit Select
                Case "m"c, "M"c
                    unsuffixedInteger = NumberKind.Decimal
                    Me.NextChar
                    Exit Select
                Case "."c
                    unsuffixedInteger = NumberKind.Double
                    buffer.Append("."c)
                    Me.NextChar
                    unsuffixedInteger = Me.ScanFraction(buffer)
                    Exit Select
                Case Else
                    unsuffixedInteger = Me.ScanOptionalIntegerSuffix
                    Exit Select
            End Select
            Dim s As String = buffer.ToString
            Select Case unsuffixedInteger
                Case NumberKind.Float
                    integerLiteral = TokenID.FloatLiteral
                    Try 
                        Me.tokenValue = Single.Parse(s, (NumberStyles.AllowExponent Or NumberStyles.AllowDecimalPoint), CultureInfo.InvariantCulture)
                        Return integerLiteral
                    Catch exception As Exception
                        str = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidFloatingPointConstant, New Object() { exception.Message })
                        Throw New RuleSyntaxException(&H1A7, str, Me.tokenStartPosition)
                    End Try
                    Exit Select
                Case NumberKind.Double
                    integerLiteral = TokenID.FloatLiteral
                    Try 
                        Me.tokenValue = Double.Parse(s, (NumberStyles.AllowExponent Or NumberStyles.AllowDecimalPoint), CultureInfo.InvariantCulture)
                        Return integerLiteral
                    Catch exception2 As Exception
                        str = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidFloatingPointConstant, New Object() { exception2.Message })
                        Throw New RuleSyntaxException(&H1A7, str, Me.tokenStartPosition)
                    End Try
                    Exit Select
                Case NumberKind.Decimal
                    integerLiteral = TokenID.DecimalLiteral
                    Try 
                        Me.tokenValue = Decimal.Parse(s, (NumberStyles.AllowExponent Or NumberStyles.AllowDecimalPoint), CultureInfo.InvariantCulture)
                        Return integerLiteral
                    Catch exception3 As Exception
                        str = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidDecimalConstant, New Object() { exception3.Message })
                        Throw New RuleSyntaxException(&H1A7, str, Me.tokenStartPosition)
                    End Try
                    Exit Select
            End Select
            integerLiteral = TokenID.IntegerLiteral
            Dim num As UInt64 = 0
            Try 
                num = UInt64.Parse(s, CultureInfo.InvariantCulture)
            Catch exception4 As Exception
                str = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidIntegerConstant, New Object() { exception4.Message })
                Throw New RuleSyntaxException(&H192, str, Me.tokenStartPosition)
            End Try
            Select Case unsuffixedInteger
                Case NumberKind.UnsuffixedInteger
                    If (num <= &H7FFFFFFFFFFFFFFF) Then
                        If (num <= &H7FFFFFFF) Then
                            Me.tokenValue = CInt(num)
                            Return integerLiteral
                        End If
                        Me.tokenValue = CLng(num)
                        Return integerLiteral
                    End If
                    Me.tokenValue = num
                    Return integerLiteral
                Case NumberKind.Long
                    Me.tokenValue = CLng(num)
                    Return integerLiteral
                Case (NumberKind.Long Or NumberKind.UnsuffixedInteger), (NumberKind.Unsigned Or NumberKind.UnsuffixedInteger)
                    Return integerLiteral
                Case NumberKind.Unsigned
                    If (num > &HFFFFFFFF) Then
                        Me.tokenValue = num
                        Return integerLiteral
                    End If
                    Me.tokenValue = DirectCast(num, UInt32)
                    Return integerLiteral
                Case (NumberKind.Unsigned Or NumberKind.Long)
                    Me.tokenValue = num
                    Return integerLiteral
            End Select
            Return integerLiteral
        End Function

        Private Function ScanExponent(ByVal buffer As StringBuilder) As NumberKind
            Dim ch As Char = Me.CurrentChar
            Select Case ch
                Case "-"c, "+"c
                    buffer.Append(ch)
                    ch = Me.NextChar
                    Exit Select
            End Select
            If Not Char.IsDigit(ch) Then
                Dim message As String = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidExponentDigit, New Object() { ch })
                Throw New RuleSyntaxException(&H17E, message, Me.currentPosition)
            End If
            Do
                buffer.Append(ch)
                ch = Me.NextChar
            Loop While Char.IsDigit(ch)
            Dim kind As NumberKind = NumberKind.Double
            Dim ch2 As Char = ch
            If (ch2 <= "M"c) Then
                Select Case ch2
                    Case "D"c
                        goto Label_00B9
                    Case "E"c
                        Return kind
                    Case "F"c
                        goto Label_00C4
                    Case "M"c
                        goto Label_00D0
                End Select
                Return kind
            End If
            Select Case ch2
                Case "d"c
                    goto Label_00B9
                Case "e"c
                    Return kind
                Case "f"c
                    goto Label_00C4
                Case "m"c
                    goto Label_00D0
                Case Else
                    Return kind
            End Select
        Label_00B9:
            kind = NumberKind.Double
            Me.NextChar
            Return kind
        Label_00C4:
            kind = NumberKind.Float
            Me.NextChar
            Return kind
        Label_00D0:
            kind = NumberKind.Decimal
            Me.NextChar
            Return kind
        End Function

        Private Function ScanFraction(ByVal buffer As StringBuilder) As NumberKind
            Dim c As Char = Me.CurrentChar
            Do While Char.IsDigit(c)
                buffer.Append(c)
                c = Me.NextChar
            Loop
            Dim kind As NumberKind = NumberKind.Double
            Dim ch2 As Char = c
            If (ch2 <= "M"c) Then
                Select Case ch2
                    Case "D"c
                        goto Label_007B
                    Case "E"c
                        goto Label_0061
                    Case "F"c
                        goto Label_0086
                    Case "M"c
                        goto Label_0092
                End Select
                Return kind
            End If
            Select Case ch2
                Case "d"c
                    goto Label_007B
                Case "e"c
                    goto Label_0061
                Case "f"c
                    goto Label_0086
                Case "m"c
                    goto Label_0092
                Case Else
                    Return kind
            End Select
        Label_0061:
            buffer.Append("E"c)
            Me.NextChar
            Return Me.ScanExponent(buffer)
        Label_007B:
            kind = NumberKind.Double
            Me.NextChar
            Return kind
        Label_0086:
            kind = NumberKind.Float
            Me.NextChar
            Return kind
        Label_0092:
            kind = NumberKind.Decimal
            Me.NextChar
            Return kind
        End Function

        Private Function ScanHexNumber() As TokenID
            Dim ch As Char = Me.CurrentChar
            Dim num As Integer = Scanner.HexValue(ch)
            If (num < 0) Then
                Dim message As String = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidHexDigit, New Object() { ch })
                Throw New RuleSyntaxException(&H17F, message, Me.currentPosition)
            End If
            Dim num2 As Integer = 1
            Dim num3 As UInt64 = [CULng](num)
            num = Scanner.HexValue(Me.NextChar)
            Do While (num >= 0)
                num2 += 1
                num3 = ((num3 * [CULng](&H10)) + num)
                num = Scanner.HexValue(Me.NextChar)
            Loop
            If (num2 > &H10) Then
                Dim str2 As String = String.Format(CultureInfo.CurrentCulture, Messages.Parser_InvalidIntegerConstant, New Object() { String.Empty })
                Throw New RuleSyntaxException(&H192, str2, Me.tokenStartPosition)
            End If
            Dim integerLiteral As TokenID = TokenID.IntegerLiteral
            Select Case Me.ScanOptionalIntegerSuffix
                Case NumberKind.UnsuffixedInteger
                    If (num3 <= &H7FFFFFFFFFFFFFFF) Then
                        If (num3 <= &H7FFFFFFF) Then
                            Me.tokenValue = CInt(num3)
                            Return integerLiteral
                        End If
                        Me.tokenValue = CLng(num3)
                        Return integerLiteral
                    End If
                    Me.tokenValue = num3
                    Return integerLiteral
                Case NumberKind.Long
                    Me.tokenValue = CLng(num3)
                    Return integerLiteral
                Case (NumberKind.Long Or NumberKind.UnsuffixedInteger), (NumberKind.Unsigned Or NumberKind.UnsuffixedInteger)
                    Return integerLiteral
                Case NumberKind.Unsigned
                    If (num3 > &HFFFFFFFF) Then
                        Me.tokenValue = num3
                        Return integerLiteral
                    End If
                    Me.tokenValue = DirectCast(num3, UInt32)
                    Return integerLiteral
                Case (NumberKind.Unsigned Or NumberKind.Long)
                    Me.tokenValue = num3
                    Return integerLiteral
            End Select
            Return integerLiteral
        End Function

        Private Sub ScanIdentifier(ByVal sb As StringBuilder, <Out> ByRef hasLettersOnly As Boolean)
            Dim c As Char = Me.CurrentChar
            hasLettersOnly = Char.IsLetter(c)
            sb.Append(c)
            c = Me.NextChar
            Do While (c <> ChrW(0))
                Dim flag As Boolean = False
                If Char.IsLetter(c) Then
                    flag = True
                ElseIf Char.IsDigit(c) Then
                    flag = True
                    hasLettersOnly = False
                ElseIf (c = "_"c) Then
                    flag = True
                    hasLettersOnly = False
                End If
                If Not flag Then
                    Return
                End If
                sb.Append(c)
                c = Me.NextChar
            Loop
        End Sub

        <SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")> _
        Private Function ScanKeywordOrIdentifier() As TokenID
            Dim flag As Boolean
            Dim sb As New StringBuilder
            Me.ScanIdentifier(sb, flag)
            Dim str As String = sb.ToString
            Dim unknown As TokenID = TokenID.Unknown
            If (flag AndAlso (Me.currentToken <> TokenID.Dot)) Then
                Dim info As KeywordInfo = Nothing
                If Scanner.keywordMap.TryGetValue(str.ToLowerInvariant, info) Then
                    unknown = info.Token
                    Me.tokenValue = info.TokenValue
                    Return unknown
                End If
            End If
            unknown = TokenID.Identifier
            Me.tokenValue = str
            Return unknown
        End Function

        Private Function ScanNumber() As TokenID
            If ((Me.CurrentChar = "0"c) AndAlso (Me.PeekNextChar = "x"c)) Then
                Me.NextChar
                Me.NextChar
                Return Me.ScanHexNumber
            End If
            Return Me.ScanDecimal
        End Function

        Private Function ScanOptionalIntegerSuffix() As NumberKind
            Dim unsuffixedInteger As NumberKind = NumberKind.UnsuffixedInteger
            Dim ch2 As Char = Me.CurrentChar
            If (ch2 <= "U"c) Then
                Select Case ch2
                    Case "L"c
                        goto Label_0028
                    Case "U"c
                        goto Label_0048
                End Select
                Return unsuffixedInteger
            End If
            Select Case ch2
                Case "l"c
                    goto Label_0028
                Case "u"c
                    goto Label_0048
                Case Else
                    Return unsuffixedInteger
            End Select
        Label_0028:
            Select Case Me.NextChar
                Case "u"c, "U"c
                    unsuffixedInteger = (NumberKind.Unsigned Or NumberKind.Long)
                    Me.NextChar
                    Return unsuffixedInteger
                Case Else
                    Return NumberKind.Long
            End Select
        Label_0048:
            Select Case Me.NextChar
                Case "l"c, "L"c
                    unsuffixedInteger = (NumberKind.Unsigned Or NumberKind.Long)
                    Me.NextChar
                    Return unsuffixedInteger
            End Select
            Return NumberKind.Unsigned
        End Function

        Private Function ScanStringLiteral() As TokenID
            Dim builder As New StringBuilder
            Dim isEscaped As Boolean = False
            Dim ch As Char = Me.ScanCharacter(isEscaped)
            Do While True
                If ((ch = ChrW(0)) AndAlso Not isEscaped) Then
                    Throw New RuleSyntaxException(&H193, Messages.Parser_UnterminatedStringLiteral, Me.tokenStartPosition)
                End If
                If ((ch = """"c) AndAlso Not isEscaped) Then
                    Exit Do
                End If
                builder.Append(ch)
                ch = Me.ScanCharacter(isEscaped)
            Loop
            Me.tokenValue = builder.ToString
            Return TokenID.StringLiteral
        End Function

        Private Function ScanUnicodeEscapeSequence() As Char
            Dim num As UInt32 = 0
            Dim i As Integer
            For i = 0 To 4 - 1
                Dim num3 As Integer = Scanner.HexValue(Me.NextChar)
                num = ((&H10 * num) + DirectCast(num3, UInt32))
            Next i
            Return DirectCast(num, Char)
        End Function

        Private Function ScanVerbatimStringLiteral() As TokenID
            Dim builder As New StringBuilder
            Dim ch As Char = Me.NextChar
            Do While True
                Select Case ch
                    Case ChrW(0)
                        Throw New RuleSyntaxException(&H193, Messages.Parser_UnterminatedStringLiteral, Me.tokenStartPosition)
                    Case """"c
                        If (Me.PeekNextChar <> """"c) Then
                            Me.tokenValue = builder.ToString
                            Return TokenID.StringLiteral
                        End If
                        Me.NextChar
                        builder.Append(""""c)
                        Exit Select
                    Case Else
                        builder.Append(ch)
                        Exit Select
                End Select
                ch = Me.NextChar
            Loop
        End Function

        Private Function SkipWhitespace(ByVal ch As Char) As Char
            Do While Char.IsWhiteSpace(ch)
                ch = Me.NextChar
            Loop
            Return ch
        End Function

        Friend Sub Tokenize(ByVal tokenList As List([Of] Token))
            Dim item As Token = Nothing
            Do
                item = Me.NextToken
                tokenList.Add(item)
            Loop While (item.TokenID <> TokenID.EndOfInput)
        End Sub

        Friend Sub TokenizeForIntellisense(ByVal tokenList As List([Of] Token))
            Dim item As Token = Nothing
            Do
                Try 
                    item = Me.NextToken
                    tokenList.Add(item)
                Catch exception1 As RuleSyntaxException
                    item = New Token(TokenID.Illegal, 0, Nothing)
                    tokenList.Add(item)
                End Try
            Loop While ((Not item Is Nothing) AndAlso (item.TokenID <> TokenID.EndOfInput))
        End Sub


        ' Fields
        Private currentPosition As Integer
        Private currentToken As TokenID
        Private inputString As String
        Private inputStringLength As Integer
        Private Shared keywordMap As Dictionary([Of] String, KeywordInfo) = Scanner.CreateKeywordMap
        Private tokenStartPosition As Integer
        Private tokenValue As Object

        ' Nested Types
        Private Class KeywordInfo
            ' Methods
            Friend Sub New(ByVal token As TokenID)
                Me.New(token, Nothing)
            End Sub

            Friend Sub New(ByVal token As TokenID, ByVal tokenValue As Object)
                Me.Token = token
                Me.TokenValue = tokenValue
            End Sub


            ' Fields
            Friend Token As TokenID
            Friend TokenValue As Object
        End Class

        <Flags> _
        Private Enum NumberKind
            ' Fields
            [Decimal] = &H10
            [Double] = 8
            Float = 12
            [Long] = 2
            Unsigned = 4
            UnsuffixedInteger = 1
        End Enum
    End Class
End Namespace

